fix(output): apply finding redactions alongside secrets - #157
Conversation
Greptile SummaryThe output pipeline now combines policy-driven finding redaction with secret sanitization while preserving named secret placeholders.
Confidence Score: 5/5The pull request appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| sdk/src/unplug/pipelines/output.py | Combines policy span redaction with secret sanitization and correctly retains redaction coverage around overlapping secret spans. |
| sdk/tests/integration/test_guard_v2.py | Adds end-to-end coverage for output findings, secret ordering, overlap handling, and configured redaction modes. |
| sdk/tests/unit/pipelines/test_pipelines.py | Verifies finding-span subtraction for disjoint, covering, empty, and invalid secret spans. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Original output] --> B[Detect secret spans]
B --> C[Subtract secret spans from findings]
C --> D[Apply policy redaction to residual spans]
D --> E[Sanitize preserved secrets]
E --> F[Protected redacted_text]
Reviews (2): Last reviewed commit: "fix(output): preserve redaction around s..." | Re-trigger Greptile
chiruu12
left a comment
There was a problem hiding this comment.
Repros on dev: scan_output flags an ip_literal_url and an email, then returns redacted_text identical to the input, because the sanitizer branch dropped the findings entirely. Since Guard always constructs a SecretsSanitizer, that branch is the only one that ever ran, so url/pii/leakage redaction was dead in scan_output.
On this branch both get replaced, and a registered secret sitting inside a url span still comes out as [REDACTED:<name>] with the surrounding span redacted around it.
984 unit + integration pass (the two tests/unit/ml/test_model_store.py failures are present on dev as well and are unrelated), 178 security pass, ruff check and format clean.
Approving.
Summary
Fixes #122
OutputPipelinenow combines the existing secret sanitizer with policy-driven span redaction for output findings. Flagged URLs and other eligible non-secret findings no longer survive inredacted_text, while registered-secret and canary redaction stay covered.Checklist
dev(see BRANCHING.md)cd sdk && make check-cipasses locallysdk/README.md/sdk/docs/Notes for reviewers
Finding spans are applied against the original text before any length-changing secret sanitization. When a finding overlaps a sanitizer-detected secret span, the secret interval is subtracted from the finding span: each remaining original-coordinate segment gets policy redaction (
[BLOCKED:urls], strip, or the scanner replacement), and the secret itself keeps its named[REDACTED:<name>]placeholder from the sanitizer.Tests added: issue repro through
Guard().scan_output(), secret-before-URL ordering, a registered fake secret inside a URL finding under BLOCKED_TAGS / STRIP / REDACTED_TAGS, a leakage finding, NONE mode, and unit coverage for the span-splitting helper with two disjoint secret regions.Verified locally: full
pytest -q(1139 passed), ruff check + format, mypy, doc drift check,uv lock --check, scenario replays, attack gate, and exfil demo integration.unplug-auditreports 9/11 both with and without this change; the two failures are ML-model-not-configured on this machine, unrelated to the diff. No public API or docs change needed.AI disclosure: Drafted with AI assistance; I reviewed the diff and ran the listed checks.